package com.encyclopedia.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.encyclopedia.auth.UserDetailEntity;
import com.encyclopedia.entity.LoginUser;
import com.encyclopedia.entity.User;
import com.encyclopedia.mapper.LoginUserMapper;
import com.encyclopedia.properties.SystemProperties;
import com.encyclopedia.result.JsonRequest;
import com.encyclopedia.result.exenum.RequestException;
import com.encyclopedia.service.LoginUserService;
import com.encyclopedia.service.RedisUtils;
import com.encyclopedia.utils.TokenUtils;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.Collections;

/**
 * @author MaLiang
 * @version 1.0
 * @date 2024-04-26 19:33
 */
@Service
public class LoginUserServiceImpl implements LoginUserService, UserDetailsService {

    @Autowired
    private LoginUserMapper userMapper;

    @Resource
    @Lazy
    private AuthenticationManager authenticationManager;

    @Autowired
    private SystemProperties systemProperties;

    @Autowired
    private RedisUtils redisUtils;


    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        User user = userMapper.selectOne(wrapper);
        UserDetailEntity userDetailEntity = new UserDetailEntity();
        userDetailEntity.setUser(user);
        userDetailEntity.setPermissionList(
                Collections.singletonList(user.getRole()));
        return userDetailEntity;
    }

    @Override
    public JsonRequest<String> login(LoginUser loginUser) {
        //获取UserDetail对象
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginUser.getUsername(), loginUser.getPassword());
        //调用身份验证器验证用户信息
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        //获取实际的用户身份信息
        Object userDetails = authenticate.getPrincipal();
        //判空
        if (ObjectUtils.isEmpty(userDetails) || !(userDetails instanceof UserDetailEntity userDetails1)) {//判断对象是否是UserDetailEntity类型

            return JsonRequest.error(RequestException.LOGIN_ERROR);
        }
        //获取用户实际对象
        User user = userDetails1.getUser();
        //生成token对象
        String token = TokenUtils.createToken(user.getUserId());
        //存入
        UsernamePasswordAuthenticationToken ut = new UsernamePasswordAuthenticationToken(
                userDetails1, user.getPassword(), userDetails1.getAuthorities());
        //将权限信息放入SecurityContextHolder
        SecurityContextHolder.getContextHolderStrategy()
                .getContext().setAuthentication(ut);
        //存储当前用户信息
        redisUtils.set(systemProperties.getMapKey(),
                user.getUserId().toString(), 5 * 60 * 60);//value: 用户序列化后的字符串
        //将用户信息存入Redis数据库
        redisUtils.set(
                systemProperties.getTokenKey() + user.getUserId(), //key: login:2(数字代表ID)
                JSON.toJSONString(userDetails), 5 * 60 * 60);//value: 用户序列化后的字符串
        return JsonRequest.success(token);
    }

    @Override
    public JsonRequest register(LoginUser loginUser) {

        String encode = passwordEncoder.encode(loginUser.getPassword());
        User user = new User();
        user.setUsername(loginUser.getUsername());
        user.setPassword(encode);
        user.setStatus(0);
        int column = userMapper.insert(user);
        return JsonRequest.success(column);
    }
}
